package co.sanduche.util;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.CookieHandler;
import java.net.HttpCookie;
import java.net.URI;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.json.JSONException;
import org.json.JSONObject;

import android.content.Context;
import android.text.TextUtils;
import android.util.Log;

public class EPCookieHandler extends CookieHandler {

	private static final String VERSION_ZERO_HEADER = "Set-cookie";

	private static final String VERSION_ONE_HEADER = "Set-cookie2";
	private static final String COOKIE_HEADER = "Cookie";
	private static final String COOKIE_FILE = "Cookies";
	/** localhost => [(playsession => HttpCookie()), ()] */
	private Map<String, Map<String, HttpCookie>> hostsMap;

	private Context context;

	public EPCookieHandler(Context context) {

		this.context = context;
		loadCookies();

	}

	@SuppressWarnings("unchecked")
	private void loadCookies() {
		File file = context.getFileStreamPath(COOKIE_FILE);
		if (file.exists())
			try {

				FileInputStream fis = context.openFileInput(COOKIE_FILE);
				BufferedReader br = new BufferedReader(new InputStreamReader(
						fis));
				String line = br.readLine();
				StringBuilder sb = new StringBuilder();
				while (line != null) {
					sb.append(line);
					line = br.readLine();
				}
				br.close();
				// Log.d("EPCookieHandler.loadCookies", sb.toString());
				JSONObject jsonuris = new JSONObject(sb.toString());
				hostsMap = new HashMap<String, Map<String, HttpCookie>>();
				Iterator<String> jsonurisiter = jsonuris.keys();

				while (jsonurisiter.hasNext()) {
					String prop = jsonurisiter.next();
					HashMap<String, HttpCookie> cookiesMap = new HashMap<String, HttpCookie>();
					JSONObject jsoncookies = jsonuris.getJSONObject(prop);
					Iterator<String> jsoncookiesiter = jsoncookies.keys();
					while (jsoncookiesiter.hasNext()) {
						String pprop = jsoncookiesiter.next();
						cookiesMap.put(pprop,
								jsonToCookie(jsoncookies.getJSONObject(pprop)));
					}
					hostsMap.put(prop, cookiesMap);

				}

			} catch (Exception e) {

				e.printStackTrace();
			}
		else {
			hostsMap = new HashMap<String, Map<String, HttpCookie>>();
		}
	}

	@Override
	public Map<String, List<String>> get(URI uri, Map<String, List<String>> arg1)
			throws IOException {
		String host = uri.getHost();
		Log.d("EPCookieHandler.get", "getting Cookies for domain: " + host);
		return get(host);
	}

	/**
	 * @see CookieHandler#get(URI, Map)
	 * @param host
	 * @return
	 */
	public Map<String, List<String>> get(String host) {
		Map<String, HttpCookie> cookies = hostsMap.get(host);
		if (cookies != null)
			for (Entry<String, HttpCookie> cookie : cookies.entrySet()) {
				if (cookie.getValue().hasExpired()) {
					cookies.remove(cookie.getKey());
				}
			}

		if (cookies == null || cookies.isEmpty()) {
			// Log.d("EPCookieHandler.get", "======");
			return Collections.emptyMap();
		}
		// Log.d("EPCookieHandler.get",
		// "Cookie : " + TextUtils.join("; ", cookies.values()));
		// Log.d("EPCookieHandler.get", "======");
		return Collections.singletonMap(COOKIE_HEADER, Collections
				.singletonList(TextUtils.join("; ", cookies.values())));
	}

	public HttpCookie getCookie(String host, String cookieName) {
		Map<String, HttpCookie> cookies = hostsMap.get(host);
		HttpCookie res = null;
		if (cookies != null) {
			HttpCookie httpCookie = cookies.get(cookieName);
			if (httpCookie != null && httpCookie.hasExpired())
				cookies.remove(cookieName);
			else
				res = httpCookie;
		}
		return res;
	}

	@Override
	public void put(URI uri, Map<String, List<String>> arg1) throws IOException {
		Map<String, HttpCookie> cookies = parseCookies(arg1);
		// Log.d("EPCookieHandler.put",
		// "saving Cookies for domain: " + uri.getHost());

		addCookies(uri, cookies);
		// Log.d("EPCookieHandler.put",
		// "Cookie : " + TextUtils.join("; ", cookies.values()));
		// Log.d("EPCookieHandler.put", "======");

	}

	private void addCookies(URI uri, Map<String, HttpCookie> cookies) {
		if (!cookies.isEmpty()) {
			if (hostsMap.get(uri.getHost()) == null) {
				hostsMap.put(uri.getHost(), cookies);
			} else {
				hostsMap.get(uri.getHost()).putAll(cookies);
			}
			saveCookies();
		}
	}

	private void saveCookies() {
		try {
			FileOutputStream fos = context.openFileOutput(COOKIE_FILE,
					Context.MODE_PRIVATE);

			JSONObject jsonuris = new JSONObject();
			for (Entry<String, Map<String, HttpCookie>> uris : hostsMap
					.entrySet()) {
				JSONObject jsoncookies = new JSONObject();
				for (Entry<String, HttpCookie> savedCookies : uris.getValue()
						.entrySet()) {
					jsoncookies.put(savedCookies.getKey(),
							cookieToJson(savedCookies.getValue()));
				}
				jsonuris.put(uris.getKey(), jsoncookies);
			}
			fos.write(jsonuris.toString().getBytes());
			fos.close();
			// Log.d("EPCookieHandler.addCookies", jsonuris.toString());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private static JSONObject cookieToJson(HttpCookie cookie) {
		JSONObject jsoncookie = new JSONObject();
		try {
			jsoncookie.put("discard", cookie.getDiscard());
			jsoncookie.put("maxAge", cookie.getMaxAge());
			jsoncookie.put("secure", cookie.getSecure());
			jsoncookie.put("version", cookie.getVersion());
			jsoncookie.put("comment", cookie.getComment());
			jsoncookie.put("commentURL", cookie.getCommentURL());
			jsoncookie.put("domain", cookie.getDomain());
			jsoncookie.put("name", cookie.getName());
			jsoncookie.put("path", cookie.getPath());
			jsoncookie.put("portlist", cookie.getPortlist());
			jsoncookie.put("value", cookie.getValue());

		} catch (JSONException e) {

			e.printStackTrace();
		}

		return jsoncookie;
	}

	private static HttpCookie jsonToCookie(JSONObject jsonObject) {
		HttpCookie httpCookie;
		try {
			httpCookie = new HttpCookie(jsonObject.getString("name"),
					jsonObject.getString("value"));
			if (jsonObject.has("comment"))
				httpCookie.setComment(jsonObject.getString("comment"));
			if (jsonObject.has("commentURL"))
				httpCookie.setCommentURL(jsonObject.getString("commentURL"));
			if (jsonObject.has("discard"))
				httpCookie.setDiscard(jsonObject.getBoolean("discard"));
			if (jsonObject.has("domain"))
				httpCookie.setDomain(jsonObject.getString("domain"));
			if (jsonObject.has("maxAge"))
				httpCookie.setMaxAge(jsonObject.getLong("maxAge"));
			if (jsonObject.has("path"))
				httpCookie.setPath(jsonObject.getString("path"));
			if (jsonObject.has("portlist"))
				httpCookie.setPortlist(jsonObject.getString("portlist"));
			if (jsonObject.has("secure"))
				httpCookie.setSecure(jsonObject.getBoolean("secure"));
			if (jsonObject.has("version"))
				httpCookie.setVersion(jsonObject.getInt("version"));
			return httpCookie;
		} catch (JSONException e) {

			e.printStackTrace();
		}
		return null;

	}

	private Map<String, HttpCookie> parseCookies(Map<String, List<String>> map) {
		Map<String, HttpCookie> response = new HashMap<String, HttpCookie>();

		for (Entry<String, List<String>> e : map.entrySet()) {
			String key = e.getKey();
			if (key != null
					&& (key.equalsIgnoreCase(VERSION_ONE_HEADER) || key
							.equalsIgnoreCase(VERSION_ZERO_HEADER))) {
				for (String cookie : e.getValue()) {
					try {
						for (HttpCookie htpc : HttpCookie.parse(cookie)) {
							response.put(htpc.getName(), htpc);
						}
					} catch (Exception e1) {

						Log.e("EPCookieHandler.parseCookies",
								"Error parsing cookies", e1);
					}
				}

			}
		}
		return response;

	}
}